package io.rocketman.transport.client;


import io.rocketman.codec.Codec;
import io.rocketman.transport.NetworkTransportException;
import io.rocketman.transport.channel.Channel;
import io.rocketman.transport.channel.handler.ChannelHandler;

import java.net.InetSocketAddress;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author He Peng
 * @create 2018-05-25 2:09
 * @update 2018-05-25 2:09
 * @updatedesc : 更新说明
 * @see
 */
public abstract class AbstractClient implements Client {

    protected ChannelHandler channelHandler;
    protected InetSocketAddress remoteAddress;
    private Codec codec;
    protected AtomicBoolean isOpen = new AtomicBoolean(false);

    protected AbstractClient(InetSocketAddress remoteAddress) throws OpenNetworkClientException {
        this.remoteAddress = remoteAddress;
        open(remoteAddress);
    }

    @Override
    public void open(InetSocketAddress remoteAddress) throws OpenNetworkClientException {
        try {
            if (! this.isOpen.get()) {
                executeOpen(remoteAddress);
            }
        } catch (Throwable t) {
            throw new OpenNetworkClientException();
        }
    }

    @Override
    public Future connect() throws NetworkTransportException {
        try {
            Channel channel = getChannel();
            boolean isDisconnected = null == channel || (channel != null && channel.isClose());
            if (! isDisconnected) {
                Future future = executeConnect();
                connectPostProcess();
                return future;
            }
            return getConnectFuture();
        } catch (Throwable t) {
            throw new NetworkTransportException(null , this.remoteAddress , t.getMessage() , t);
        }
    }

    protected abstract void connectPostProcess() throws NetworkTransportException;

    @Override
    public Future request(Object message) throws NetworkTransportException {

        // TODO 编解码 、 序列化 ,将 Object 处理成 byte[]
        byte[] bytes = this.codec.encode(message);
        try {
            return executeRequest(bytes);
        } catch (Throwable t) {
            throw new NetworkTransportException(null , this.remoteAddress , t.getMessage() , t);
        }
    }

    protected abstract Future executeRequest(Object message) throws Throwable;

    @Override
    public ChannelHandler getChannelHandler() {
        return this.channelHandler;
    }

    protected abstract Future getConnectFuture();

    protected abstract Future executeConnect() throws Throwable;

    protected abstract void executeOpen(InetSocketAddress remoteAddress) throws Throwable;
}
